Claude Code Plugins

Community-maintained marketplace

Feedback

Reverse Proxy Deployment

@lawless-m/Gwen
0
0

Deploy web applications behind Apache reverse proxy on rivsprod01 with relative URLs and proper path configuration

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name Reverse Proxy Deployment
description Deploy web applications behind Apache reverse proxy on rivsprod01 with relative URLs and proper path configuration

Reverse Proxy Deployment

Guide for deploying web applications behind the Apache reverse proxy on rivsprod01 (dw.ramsden-international.com). Covers frontend relative URL patterns and Apache ProxyPass configuration.

Instructions

When deploying a web application that will be accessed through the reverse proxy:

  1. Use Relative URLs: Frontend code must use relative URLs (not absolute localhost URLs) to work behind the proxy
  2. Configure ProxyPass on rivsprod01: Create Apache config in /etc/apache2/proxy-conf.d/ with proper path stripping
  3. Order Matters: More specific paths must come before general paths in Apache config
  4. Test Locally First: Verify services are accessible from rivsprod01 before configuring proxy
  5. Use Trailing Slashes: Both source and target URLs need trailing slashes for path stripping to work

Examples

Example 1: Deploy Web Application with API Backend

User: I have a web app with frontend on port 9273 and API on port 8765. Deploy it behind the proxy at /myapp/

Claude: I'll set up your application for reverse proxy deployment:

1. **Update Frontend URLs**: Change API calls to use relative URLs
   - Before: `fetch('http://localhost:8765/api/status')`
   - After: `fetch('api/status')`  // Relative to current path

2. **Create Apache Config**: SSH to rivsprod01 and create `/etc/apache2/proxy-conf.d/myapp.conf`
   - API path: `/myapp/api/` → backend on port 8765
   - Frontend path: `/myapp/` → frontend on port 9273
   - API location must come FIRST (more specific)

3. **Reload Apache**: `sudo systemctl reload apache2`

[Provides implementation using the ProxyPass Configuration pattern below]

Example 2: Frontend Uses Absolute URLs

User: My frontend has `fetch('http://localhost:3000/api/data')` hardcoded. How do I make it work behind a proxy?

Claude: Absolute URLs won't work behind a reverse proxy. You need to update the frontend to use relative URLs:

**Options:**
1. **Best: Use relative URLs** - `fetch('api/data')` - works anywhere
2. **Alternative: Use base path** - Store base path in config, prepend to all API calls
3. **Hidden input method** - Store proxy path in HTML, read in JavaScript

For option 1 (recommended):
- Replace all `http://localhost:3000/api/` with `api/`
- The browser resolves relative to current page path
- If page is at `/myapp/`, API call goes to `/myapp/api/`

[Shows the Relative URL Pattern implementation below]

Example 3: Multiple Services on Same Machine

User: I have 3 services running on ports 8001, 8002, 8003. Deploy all at /service1/, /service2/, /service3/

Claude: I'll configure all three services in a single Apache config file:

1. **Create single config file**: `/etc/apache2/proxy-conf.d/services.conf`
2. **Add ProxyPass for each**: More specific paths first (doesn't matter here since no overlap)
3. **Each service gets clean URLs**: Paths are stripped before forwarding
4. **Reload once**: All services go live together

[Provides implementation using the Multi-Service Configuration pattern below]

Example 4: API Calls Return 404

User: My frontend loads but API calls return 404. Frontend is at /rabbit/, API should be at /rabbit/api/

Claude: The issue is likely ProxyPass configuration. Let me check:

1. **Verify services are reachable**: From rivsprod01, can you curl the backend directly?
   - `curl http://10.99.0.3:8765/status` should work

2. **Check ProxyPass order**: API location must come BEFORE frontend location
   - Wrong order: frontend `/rabbit/` catches `/rabbit/api/` requests
   - Right order: API `/rabbit/api/` catches first, then frontend `/rabbit/`

3. **Verify trailing slashes**: Both paths need trailing slashes for stripping
   - `ProxyPass /rabbit/api/ http://10.99.0.3:8765/`
   - Without trailing slash, path isn't stripped properly

[Shows debugging steps from Troubleshooting section below]

Reference Implementation Details

The sections below contain proven working configurations from production deployments.

Reference Files in This Folder:

  • rabbit.conf - Example Apache config from Invoice OCR deployment

Relative URL Pattern

Purpose: Make frontend work behind any reverse proxy path without hardcoding URLs

HTML Method (Recommended for Simple Cases)

<!-- Hidden input stores the API base path -->
<input type="hidden" id="serverUrl" value="api">

<script>
function getServerUrl() {
    return document.getElementById('serverUrl').value.trim();
}

// Use in fetch calls
async function checkStatus() {
    const res = await fetch(`${getServerUrl()}/status`);
    const data = await res.json();
    // ...
}
</script>

Key Points:

  • Value is "api" (relative) not "http://localhost:8765" (absolute)
  • Browser resolves api/status relative to current page
  • If page is at https://example.com/rabbit/, request goes to https://example.com/rabbit/api/status
  • Proxy strips /rabbit/ and forwards to backend

JavaScript Config Method (For Complex Applications)

// config.js
const CONFIG = {
    API_BASE: 'api',  // Relative to current path
    WS_BASE: 'ws'     // WebSocket endpoint if needed
};

// Use throughout app
fetch(`${CONFIG.API_BASE}/endpoint`)

When to use:

  • Multiple API endpoints
  • Different base paths for dev/staging/prod
  • Need to change paths without editing HTML

ProxyPass Configuration Pattern

Purpose: Configure Apache to forward requests from public path to internal service

Basic Single-Service Configuration

File: /etc/apache2/proxy-conf.d/myservice.conf

# Single service on custom path
ProxyPass /myservice/ http://10.99.0.3:8080/
ProxyPassReverse /myservice/ http://10.99.0.3:8080/

Key Points:

  • Simple ProxyPass directives (no <Location> blocks needed)
  • Trailing slashes on both source and target strip the path prefix
  • Request to /myservice/page becomes /page at backend
  • ProxyPassReverse rewrites response headers (redirects, etc.)

API + Frontend Configuration

File: /etc/apache2/proxy-conf.d/service-with-api.conf

# Backend API - Must come FIRST (more specific path)
ProxyPass /rabbit/api/ http://10.99.0.3:8765/
ProxyPassReverse /rabbit/api/ http://10.99.0.3:8765/

# Frontend - Comes SECOND (less specific path)
ProxyPass /rabbit/ http://10.99.0.3:9273/
ProxyPassReverse /rabbit/ http://10.99.0.3:9273/

Key Points:

  • API location MUST be listed first (more specific)
  • If frontend is listed first, it catches API requests → 404
  • Both locations strip their prefix before forwarding
  • Request flow:
    • GET /rabbit/api/status → matches first rule → GET /status to port 8765
    • GET /rabbit/index.html → matches second rule → GET /index.html to port 9273

Large File Upload Configuration

# Service that handles file uploads (PDFs, images, etc.)
ProxyPass /uploads/ http://10.99.0.3:7000/
ProxyPassReverse /uploads/ http://10.99.0.3:7000/

# Important for large PDF uploads
<Location /uploads/>
    ProxyPass http://10.99.0.3:7000/
    ProxyPassReverse http://10.99.0.3:7000/

    # Allow 50MB uploads
    LimitRequestBody 52428800
</Location>

When to use:

  • File upload services
  • PDF/image processing
  • Any endpoint that receives large request bodies

Multi-Service Configuration Pattern

Purpose: Deploy multiple independent services in one config file

File: /etc/apache2/proxy-conf.d/all-services.conf

# Service 1: API Gateway
ProxyPass /api/ http://10.99.0.3:8001/
ProxyPassReverse /api/ http://10.99.0.3:8001/

# Service 2: Admin Dashboard
ProxyPass /admin/ http://10.99.0.3:8002/
ProxyPassReverse /admin/ http://10.99.0.3:8002/

# Service 3: Public Website
ProxyPass /site/ http://10.99.0.3:8003/
ProxyPassReverse /site/ http://10.99.0.3:8003/

Key Points:

  • Each service is completely independent
  • Order doesn't matter if paths don't overlap
  • All go live together when Apache reloads
  • Can comment out individual services to disable temporarily

Deployment Workflow

Standard deployment process for new service:

1. Verify Local Service Accessibility

# From local machine where service runs
curl http://10.99.0.3:8765/status  # Test your port

# From rivsprod01 (SSH in)
ssh rivsprod01 "curl -s http://10.99.0.3:8765/status"

Expected: JSON response or HTML, not connection refused

2. Create Apache Configuration

# SSH to rivsprod01
ssh rivsprod01

# Create config file (as root or with sudo)
sudo nano /etc/apache2/proxy-conf.d/myservice.conf

# Add ProxyPass configuration (see patterns above)

# Verify syntax (optional, but recommended)
# apache2ctl configtest   # May not be available
# Just proceed to reload if command not found

3. Reload Apache

sudo systemctl reload apache2

# Verify Apache is still running
sudo systemctl status apache2

4. Test Public Access

# From any machine
curl https://dw.ramsden-international.com/myservice/

# Or open in browser

Troubleshooting

404 Not Found - Service Works Locally

Cause: ProxyPass configuration issue

Diagnostic Steps:

  1. Verify service is accessible from rivsprod01:

    ssh rivsprod01 "curl -s http://10.99.0.3:PORT/endpoint"
    
  2. Check Apache config order:

    ssh rivsprod01 "cat /etc/apache2/proxy-conf.d/myservice.conf"
    
    • API paths must come before frontend paths
    • Verify trailing slashes on both source and target
  3. Check Apache error logs:

    ssh rivsprod01 "sudo tail -50 /var/log/apache2/error.log | grep myservice"
    

Solution:

  • Fix ProxyPass order (more specific first)
  • Add missing trailing slashes
  • Reload Apache: sudo systemctl reload apache2

404 on API Calls, Frontend Works

Cause: Frontend path is catching API requests

Example of Wrong Configuration:

# WRONG - Frontend catches everything
ProxyPass /app/ http://10.99.0.3:9000/
ProxyPass /app/api/ http://10.99.0.3:8000/

Solution - Put API First:

# CORRECT - API catches specific path first
ProxyPass /app/api/ http://10.99.0.3:8000/
ProxyPass /app/ http://10.99.0.3:9000/

Connection Refused from rivsprod01

Cause: Service not listening on accessible IP

Diagnostic:

# On machine running service
netstat -tlnp | grep PORT
# or
ss -tlnp | grep PORT

Look for:

  • 127.0.0.1:PORT - Only listening on localhost (wrong)
  • 10.99.0.3:PORT - Listening on network IP (correct)
  • 0.0.0.0:PORT - Listening on all interfaces (also correct)

Solution: Configure service to bind to 0.0.0.0 or specific IP 10.99.0.3

Service Stops Working After Apache Reload

Cause: Configuration syntax error

Diagnostic:

ssh rivsprod01 "sudo systemctl status apache2"

Solution:

  1. Check for typos in ProxyPass URLs
  2. Verify no missing quotes or slashes
  3. Look at error log: sudo tail /var/log/apache2/error.log
  4. Fix config and reload again

CORS Errors in Browser Console

Cause: Backend not configured for CORS, or wrong origin

Solution (Backend): Enable CORS in your service

# FastAPI example
from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Or specific domain
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Note: Proxy handles forwarding; backend sees requests from proxy IP, not client

IP Addresses Reference

Hostname IP Address Purpose
rivsprod01 10.99.0.2 Reverse proxy server (Apache)
pogs (local) 10.99.0.3 Development machine running services

Service Configuration:

  • Services should bind to 10.99.0.3 or 0.0.0.0 to be accessible from rivsprod01
  • Use http://10.99.0.3:PORT in ProxyPass target URLs
  • Never use localhost or 127.0.0.1 in ProxyPass targets

File Locations on rivsprod01

Path Purpose
/etc/apache2/proxy-conf.d/*.conf Proxy configurations (add yours here)
/etc/apache2/sites-available/default-ssl.conf Main SSL site config (includes proxy-conf.d)
/var/log/apache2/error.log Apache error log
/var/log/apache2/access.log Access log (if needed)

Important: Configs in /etc/apache2/proxy-conf.d/ are automatically included by the SSL site configuration.

Best Practices Summary

  1. Always use relative URLs in frontend code for proxy compatibility
  2. Test service accessibility from rivsprod01 before configuring proxy
  3. Put specific paths first in Apache config (API before frontend)
  4. Use trailing slashes on both ProxyPass source and target for path stripping
  5. Reload Apache after config changes: sudo systemctl reload apache2
  6. Keep configs organized - one file per application or related service group
  7. Document your paths - add comments explaining what each ProxyPass does
  8. Test both frontend and API after deployment to verify routing